package com.concurrent.sample.business.service.impl;

import com.concurrent.sample.business.entity.OrderEntity;
import com.concurrent.sample.business.dto.debug.AppDebugInfoDTO;
import com.concurrent.sample.business.dto.debug.DataMemoryTypeEnum;
import com.concurrent.sample.business.dto.report.TradeExecReportDTO;
import com.concurrent.sample.business.repo.OrderRepo;
import com.concurrent.sample.business.service.OrderService;
import com.concurrent.sample.common.util.LongUtil;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
@Slf4j
public class OrderServiceImpl implements OrderService {

  public static Map<Long, OrderEntity> ID_CONTAINER = new HashMap<>();

  public static Map<Long, OrderEntity> EVENT_ID_CONTAINER = new HashMap<>();

  private static AtomicLong idAtomic = new AtomicLong(0);

  private final OrderRepo orderRepo;

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void save(List<OrderEntity> orderEntities) {
    if(AppDebugInfoDTO.dataMemoryType == DataMemoryTypeEnum.LOCAL){
      for (OrderEntity orderEntity : orderEntities){
        orderEntity.setId(idAtomic.incrementAndGet());
        ID_CONTAINER.put(orderEntity.getId(), orderEntity);
        EVENT_ID_CONTAINER.put(orderEntity.getEventId(), orderEntity);
      }
    } else {
      orderRepo.saveAll(orderEntities);
    }
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public OrderEntity updateByExecutionReport(TradeExecReportDTO execReport) {
    OrderEntity orderEntity = getById(execReport.getOriginalOrderId());

    // 更新订单状态、数量
    orderEntity.setOrderStatus(execReport.getOrderStatus())
        .setLeaveQty(LongUtil.minusByNullToZero(orderEntity.getLeaveQty(), execReport.getQuantity()))
        .setExecPrice(execReport.getExecPrice())
        .setMemo(execReport.getMemo())
    ;

    return orderEntity;
  }

  @Override
  public OrderEntity getById(Long id) {
    if(AppDebugInfoDTO.dataMemoryType == DataMemoryTypeEnum.LOCAL){
      return ID_CONTAINER.get(id);
    } else {
      return orderRepo.findById(id).orElse(null);
    }
  }

  @Override
  public List<OrderEntity> getByIds(List<Long> ids) {
    List<OrderEntity> orderEntities = new ArrayList<>();
    if(AppDebugInfoDTO.dataMemoryType == DataMemoryTypeEnum.LOCAL){
      for(Long id : ids){
        orderEntities.add(ID_CONTAINER.get(id));
      }
    } else {
      orderEntities.addAll(orderRepo.findAllById(ids));
    }
    return orderEntities;
  }

  @Override
  public OrderEntity getByEventId(Long eventId) {
    if(AppDebugInfoDTO.dataMemoryType == DataMemoryTypeEnum.LOCAL){
      return EVENT_ID_CONTAINER.get(eventId);
    } else {
      return orderRepo.findByEventId(eventId);
    }
  }

}
